home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / SciAn / src / ScianAnimation.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  36KB  |  1,574 lines

  1. /*ScianAnimation.c
  2.   Eric Pepke
  3.   21 May 1993
  4.  
  5.   Advanced keyframe animation for SciAn
  6. */
  7.  
  8. #include "Scian.h"
  9. #include "ScianTypes.h"
  10. #include "ScianIDs.h"
  11. #include "ScianNames.h"
  12. #include "ScianWindows.h"
  13. #include "ScianObjWindows.h"
  14. #include "ScianDialogs.h"
  15. #include "ScianScripts.h"
  16. #include "ScianErrors.h"
  17. #include "ScianSymbols.h"
  18. #include "ScianEvents.h"
  19. #include "ScianLists.h"
  20. #include "ScianArrays.h"
  21. #include "ScianControls.h"
  22. #include "ScianButtons.h"
  23. #include "ScianTextBoxes.h"
  24. #include "ScianTitleBoxes.h"
  25. #include "ScianIcons.h"
  26. #include "ScianStyle.h"
  27. #include "ScianObjFunctions.h"
  28. #include "ScianDatabase.h"
  29. #include "ScianColors.h"
  30. #include "ScianObjFunctions.h"
  31. #include "ScianTemplates.h"
  32. #include "ScianTemplateHelper.h"
  33. #include "ScianSnap.h"
  34. #include "ScianAnimation.h"
  35. #include "ScianTrackControls.h"
  36. #include "ScianDraw.h"
  37. #include "ScianMethods.h"
  38.  
  39. #define P2T(p)    ((((p) - l) * (maxTime - minTime) / ((real) r - l)) + minTime)
  40. #define T2P(t)    floor(((((t) - minTime) * ((real) r - l) / (maxTime - minTime)) + l) + 0.5)
  41.  
  42. ObjPtr sequenceClass;        /*Class of a sequence*/
  43. ObjPtr trackClass;        /*Class of a track within a sequence*/
  44. ObjPtr subTrackClass;        /*Class of a subtrack within a track*/
  45. ObjPtr keyFrameClass;        /*Class of a keyframe within a subtrack*/
  46.  
  47. char **betterVarNames = 0;    /*Better variable names*/
  48. int nBetterVarNames = 0;    /*Number of better var names*/
  49.  
  50. #ifdef PROTO
  51. static ObjPtr NewTrack(ObjPtr class, ObjPtr repObj)
  52. #else
  53. static ObjPtr NewTrack(class, repObj)
  54. ObjPtr class;
  55. ObjPtr repObj;
  56. #endif
  57. /*Creates a new track to control repObj*/
  58. {
  59.     ObjPtr retVal;
  60.  
  61.     retVal = NewObject(class ? class : trackClass, 0L);
  62.     SetVar(retVal, REPOBJ, repObj);
  63.     MakeVar(repObj, NAME);
  64.     SetVar(retVal, NAME, GetVar(repObj, NAME));
  65.     return retVal;
  66. }
  67.  
  68. #ifdef PROTO
  69. static ObjPtr NewSubTrack(ObjPtr class, ObjPtr repObj, char *name)
  70. #else
  71. static ObjPtr NewSubTrack(class, repObj, name)
  72. ObjPtr class;
  73. ObjPtr repObj;
  74. char *name;
  75. #endif
  76. /*Creates a new subtrack to control repObj's variable group named name*/
  77. {
  78.     ObjPtr retVal;
  79.  
  80.     retVal = NewObject(class ? class : subTrackClass, 0L);
  81.     SetVar(retVal, REPOBJ, repObj);
  82.     SetVar(retVal, NAME, NewString(name));
  83.     return retVal;
  84. }
  85.  
  86. #ifdef PROTO
  87. static ObjPtr NewKeyFrame(int whichFrame, ObjPtr snapshot)
  88. #else
  89. static ObjPtr NewKeyFrame(whichFrame, snapshot)
  90. int whichFrame;
  91. ObjPtr snapshot;
  92. #endif
  93. /*Makes a new keyframe at time using snapshot.*/
  94. {
  95.     ObjPtr retVal;
  96.  
  97.     retVal = NewObject(keyFrameClass, 0L);
  98.     SetVar(retVal, WHICHFRAME, NewInt(whichFrame));
  99.     SetVar(retVal, SNAPSHOT, snapshot);
  100.  
  101.     return retVal;
  102. }
  103.  
  104. #ifdef PROTO
  105. void InsertKeySnapshot(ObjPtr track, int whichFrame, ObjPtr snapshot)
  106. #else
  107. void InsertKeySnapshot(track, whichFrame, snapshot)
  108. ObjPtr track, snapshot;
  109. int whichFrame;
  110. #endif
  111. /*Inserts a key snapshot at frame whichFrame into track, or just updates 
  112.   what's there.*/
  113. {
  114.     ObjPtr keyframes;
  115.     ThingListPtr runner;
  116.     long index;
  117.     long dim;
  118.     ObjPtr *elements;
  119.     ObjPtr var;
  120.  
  121.     keyframes = GetVar(track, KEYFRAMES);
  122.     if (!keyframes)
  123.     {
  124.     dim = 1;
  125.     keyframes = NewArray(AT_OBJECT, 1, &dim);
  126.     index = 0;
  127.  
  128.     elements = ELEMENTS(keyframes);
  129.     elements[0] = NewKeyFrame(whichFrame, snapshot);
  130.     SetVar(track, KEYFRAMES, keyframes);
  131.     }
  132.     else
  133.     {
  134.     /*Search to see if there is already a keyframe there*/
  135.     index = SearchIntVar(keyframes, WHICHFRAME, whichFrame);
  136.  
  137.     elements = ELEMENTS(keyframes);
  138.  
  139.     if (index > 0)
  140.     {
  141.         /*See if the element just before is the one*/
  142.         MakeVar(elements[index - 1], WHICHFRAME);
  143.         var = GetVar(elements[index - 1], WHICHFRAME);
  144.         if (var && IsInt(var) && GetInt(var) == whichFrame)
  145.         {
  146.         /*Found it!  Just change it's snapshot, touch the keyframe, 
  147.           and return*/
  148.  
  149.         SetVar(elements[index - 1], SNAPSHOT, snapshot);
  150.         SetVar(track, KEYFRAMES, keyframes);
  151.         return;
  152.         }
  153.     }
  154.  
  155.     /*Insert keyframe where it belongs*/
  156.     keyframes = InsertInArray(keyframes,
  157.         NewKeyFrame(whichFrame, snapshot), index);
  158.     SetVar(track, KEYFRAMES, keyframes);
  159.     }
  160. }
  161.  
  162. #ifdef PROTO
  163. ObjPtr TrackObjectWithinSequence(ObjPtr sequence, ObjPtr object, ObjPtr trackClass)
  164. #else
  165. ObjPtr TrackObjectWithinSequence(sequence, object, trackClass)
  166. ObjPtr sequence;
  167. ObjPtr object;
  168. ObjPtr trackClass;
  169. #endif
  170. /*Returns the track for object within sequence or adds one*/
  171. {
  172.     ObjPtr tracks, track, var;
  173.     ObjPtr *elements;
  174.     long k, dim;
  175.  
  176.     /*First find out if there is a track with that object*/
  177.     MakeVar(sequence, TRACKS);
  178.     tracks = GetVar(sequence, TRACKS);
  179.     if (tracks)
  180.     {
  181.     for (k = 0; k < DIMS(tracks)[0]; ++k)
  182.     {
  183.         var = GetObjectElement(tracks, &k);
  184.         if (GetVar(var, REPOBJ) == object)
  185.         {
  186.         return var;
  187.         }
  188.     }
  189.     }
  190.  
  191.     /*Fell through, object not found.  Create a new track*/
  192.     track = NewTrack(trackClass, object);
  193.  
  194.     if (tracks)
  195.     {
  196.     /*Insert track in sorted place*/
  197.     var = GetStringVar("TrackObjectWithinSequence", object, NAME);
  198.     if (!var) return NULLOBJ;
  199.     k = SearchStringVar(tracks, NAME, GetString(var));
  200.     if (k < 0) return NULLOBJ;
  201.     tracks = InsertInArray(tracks, track, k);
  202.     }
  203.     else
  204.     {
  205.     /*Create single array to hold tracks*/
  206.     dim = 1;
  207.     tracks = NewArray(AT_OBJECT, 1, &dim);
  208.     elements = (ObjPtr *) ELEMENTS(tracks);
  209.     elements[0] = track;
  210.     }
  211.     SetVar(track, PARENT, sequence);
  212.  
  213.     SetVar(sequence, TRACKS, tracks);
  214.     return track;
  215. }
  216.  
  217. #ifdef PROTO
  218. ObjPtr GetTrackedObjectWithinSequence(ObjPtr sequence, ObjPtr object)
  219. #else
  220. ObjPtr GetTrackedObjectWithinSequence(sequence, object)
  221. ObjPtr sequence;
  222. ObjPtr object;
  223. #endif
  224. /*Returns the track for object within sequence or returns NULLOBJ*/
  225. {
  226.     ObjPtr tracks, track, var;
  227.     ObjPtr *elements;
  228.     long k, dim;
  229.  
  230.     /*First find out if there is a track with that object*/
  231.     MakeVar(sequence, TRACKS);
  232.     tracks = GetVar(sequence, TRACKS);
  233.     if (tracks)
  234.     {
  235.     for (k = 0; k < DIMS(tracks)[0]; ++k)
  236.     {
  237.         var = GetObjectElement(tracks, &k);
  238.         if (GetVar(var, REPOBJ) == object)
  239.         {
  240.         return var;
  241.         }
  242.     }
  243.     }
  244.  
  245.     /*Fell through, object not found.*/
  246.     return NULLOBJ;
  247. }
  248.  
  249. #ifdef PROTO
  250. ObjPtr TrackVarGroupWithinSequence(ObjPtr sequence, ObjPtr object, char *group, ObjPtr trackClass)
  251. #else
  252. ObjPtr TrackVarGroupWithinSequence(sequence, object, group, trackClass)
  253. ObjPtr sequence;
  254. ObjPtr object;
  255. char *group;
  256. ObjPtr trackClass;
  257. #endif
  258. /*Returns the track for vargroup group of object within sequence
  259.   or adds one*/
  260. {
  261.     ObjPtr track, var, name;
  262.     ObjPtr subTracks, subTrack;
  263.     ObjPtr *elements;
  264.     long k, dim;
  265.  
  266.     track = TrackObjectWithinSequence(sequence, object, NULLOBJ);
  267.  
  268.     /*First find out if there is a subtrack for that group*/
  269.     MakeVar(track, SUBTRACKS);
  270.     subTracks = GetVar(track, SUBTRACKS);
  271.     if (subTracks)
  272.     {
  273.     for (k = 0; k < DIMS(subTracks)[0]; ++k)
  274.     {
  275.         var = GetObjectElement(subTracks, &k);
  276.         name = GetVar(var, NAME);
  277.         if (name && (0 == strcmp2(GetString(name), group)))
  278.         {
  279.         return var;
  280.         }
  281.     }
  282.     }
  283.  
  284.     /*Fell through, object not found.  Create a new track*/
  285.     subTrack = NewSubTrack(trackClass, object, group);
  286.  
  287.     if (IsSelected(track)) Select(subTrack, true);
  288.  
  289.     if (subTracks)
  290.     {
  291.     /*Insert track in sorted place*/
  292.     k = SearchStringVar(subTracks, NAME, group);
  293.     if (k < 0) return NULLOBJ;
  294.     subTracks = InsertInArray(subTracks, subTrack, k);
  295.     }
  296.     else
  297.     {
  298.     /*Create single array to hold tracks*/
  299.     dim = 1;
  300.     subTracks = NewArray(AT_OBJECT, 1, &dim);
  301.     elements = (ObjPtr *) ELEMENTS(subTracks);
  302.     elements[0] = subTrack;
  303.     }
  304.     SetVar(subTrack, PARENT, track);
  305.     SetVar(track, SUBTRACKS, subTracks);
  306.  
  307.     /*Also need to touch TRACKS of sequence*/
  308.     SetVar(sequence, TRACKS, GetVar(sequence, TRACKS));
  309.     return subTrack;
  310. }
  311.  
  312. #ifdef PROTO
  313. ObjPtr GetTrackedVarGroupWithinSequence(ObjPtr sequence, ObjPtr object, char *group)
  314. #else
  315. ObjPtr GetTrackedVarGroupWithinSequence(sequence, object, group)
  316. ObjPtr sequence;
  317. ObjPtr object;
  318. char *group;
  319. #endif
  320. /*Returns the track for vargroup group of object within sequence
  321.   or NULLOBJ*/
  322. {
  323.     ObjPtr track, var, name;
  324.     ObjPtr subTracks, subTrack;
  325.     ObjPtr *elements;
  326.     long k, dim;
  327.  
  328.     track = GetTrackedObjectWithinSequence(sequence, object);
  329.     if (!track) return NULLOBJ;
  330.  
  331.     /*First find out if there is a subtrack for that group*/
  332.     MakeVar(track, SUBTRACKS);
  333.     subTracks = GetVar(track, SUBTRACKS);
  334.     if (subTracks)
  335.     {
  336.     for (k = 0; k < DIMS(subTracks)[0]; ++k)
  337.     {
  338.         var = GetObjectElement(subTracks, &k);
  339.         name = GetVar(var, NAME);
  340.         if (name && (0 == strcmp2(GetString(name), group)))
  341.         {
  342.         return var;
  343.         }
  344.     }
  345.     }
  346.  
  347.     /*Fell through, object not found.*/
  348.     return NULLOBJ;
  349. }
  350.  
  351. #if 1
  352. static void toado(ObjPtr sequence, char *name)
  353. {
  354.     ObjPtr temp;
  355.     temp = NewObject(NULLOBJ, 0L);
  356.     SetVar(temp, NAME, NewString(name));
  357.     TrackVarGroupWithinSequence(sequence, temp, "Guano", NULLOBJ);
  358.     TrackVarGroupWithinSequence(sequence, temp, "Bat", NULLOBJ);
  359. }
  360. #endif
  361.  
  362. #ifdef PROTO
  363. ObjPtr NewSequence(char *name)
  364. #else
  365. ObjPtr NewSequence(name)
  366. char *name;
  367. #endif
  368. /*Returns a new sequence with name, also shows controls*/
  369. {
  370.     ObjPtr retVal;
  371.  
  372.     /*UPDATE log command to make sequence*/
  373.     retVal = NewObject(sequenceClass, 0L);
  374.     SetVar(retVal, NAME, NewString(name));
  375.     AddObjToDatabase(retVal);
  376.  
  377. #if 0
  378.     /*DEBUG give it some tracks by default*/
  379.     {
  380.     toado(retVal, "And");
  381.     toado(retVal, "Did");
  382.     toado(retVal, "Those");
  383.     toado(retVal, "Teeth");
  384.     toado(retVal, "In");
  385.     toado(retVal, "Ancient");
  386.     toado(retVal, "Times");
  387.     toado(retVal, "Walk");
  388.     toado(retVal, "Upon");
  389.     toado(retVal, "England's");
  390.     toado(retVal, "Mountains");
  391.     toado(retVal, "Green?");
  392.     }
  393. #endif
  394.  
  395.     DeferMessage(retVal, SHOWCONTROLS);
  396.  
  397.     return retVal;
  398. }
  399.  
  400. #ifdef PROTO
  401. void DoNewSequence(void)
  402. #else
  403. void DoNewSequence()
  404. #endif
  405. /*Asks the user for a name and makes the new sequence*/
  406. {
  407.     ObjPtr name;
  408.  
  409.     name = NewUniqueName("Sequence #1", CLASS_SEQUENCE);
  410.     NewSequence(GetString(name));
  411. }
  412.  
  413. #ifdef PROTO
  414. void ExpressTrack(ObjPtr track, int frame)
  415. #else
  416. void ExpressTrack(track, frame)
  417. ObjPtr track;
  418. int frame;
  419. #endif
  420. /*Expresses a track by adjusting all the variables it controls to frame*/
  421. {
  422.     ObjPtr var;
  423.     ObjPtr *elements;
  424.     long k;
  425.     FuncTyp method;
  426.  
  427.     MakeVar(track, SUBTRACKS);
  428.     var = GetVar(track, SUBTRACKS);
  429.     if (var)
  430.     {
  431.     elements = ELEMENTS(var);
  432.     for (k = 0; k < DIMS(var)[0]; ++k)
  433.     {
  434.         method = GetMethod(elements[k], EXPRESS);
  435.         if (method)
  436.         {
  437.         (*method)(elements[k], frame);
  438.         }
  439.     }
  440.     }
  441. }
  442.  
  443. static ObjPtr ExpressDefaultSubTrack(track, frame)
  444. ObjPtr track;
  445. int frame;
  446. /*Default method to express a variable group subtrack at frame*/
  447. {
  448.     ObjPtr *elements;
  449.     long index;
  450.     ObjPtr keyFrames;
  451.     ObjPtr var;
  452.     ObjPtr frame1, frame2;    /*Frames for interpolation*/
  453.     real weight;
  454.     int n1, n2;
  455.     ObjPtr newSnap;
  456.  
  457.     /*Get the keyframes*/
  458.     keyFrames = GetVar(track, KEYFRAMES);
  459.     if (!keyFrames) return ObjFalse;
  460.  
  461.     /*Find the index for this frame*/
  462.     index = SearchIntVar(keyFrames, WHICHFRAME, frame);
  463.     if (index <= 0)
  464.     {
  465.     /*Before first*/
  466.     return ObjFalse;
  467.     }
  468.  
  469.     elements = ELEMENTS(keyFrames);
  470.  
  471.     frame1 = elements[index - 1];
  472.  
  473.     /*See if it's smack dab on a frame*/
  474.     var = GetIntVar("ExpressDefaultSubTrack", frame1, WHICHFRAME);
  475.     if (!var) return ObjFalse;
  476.  
  477.     if (GetInt(var) == frame)
  478.     {
  479.     /*That's it*/
  480.     var = GetObjectVar("ExpressDefaultSubTrack", frame1, SNAPSHOT);
  481.     if (!var) return ObjFalse;
  482.     ApplySnapshot(var);
  483.     return;
  484.     }
  485.  
  486.     if (index >= DIMS(keyFrames)[0])
  487.     {
  488.     /*After the last*/
  489.     return ObjFalse;
  490.     }
  491.  
  492.     /*Have two keyframes*/
  493.     frame2 = elements[index];
  494.  
  495.     /*Calculate weight*/
  496.     var = GetVar(frame1, WHICHFRAME);
  497.     if (!var) return ObjFalse;
  498.     n1 = GetInt(var);
  499.     var = GetVar(frame2, WHICHFRAME);
  500.     if (!var) return ObjFalse;
  501.     n2 = GetInt(var);
  502.     weight = ((real) (frame - n1)) / ((real) (n2 - n1));
  503.  
  504.     newSnap = InterpSnapshots(GetVar(frame1, SNAPSHOT),
  505.             GetVar(frame2, SNAPSHOT), weight);
  506.     ApplySnapshot(newSnap);
  507. }
  508.  
  509. #ifdef PROTO
  510. void ExpressSequence(ObjPtr sequence)
  511. #else
  512. void ExpressSequence(sequence)
  513. ObjPtr sequence;
  514. #endif
  515. /*Expresses a sequence by adjusting all the variables it controls to 
  516.   the current time*/
  517. {
  518.     ObjPtr var;
  519.     real time;
  520.     int frame;
  521.     ObjPtr *elements;
  522.     long k;
  523.  
  524.     var = GetRealVar("ExpressSequence", sequence, TIME);
  525.     if (!var) return;
  526.     time = GetReal(var);
  527.  
  528.     MakeVar(sequence, FRAMERATE);
  529.     var = GetRealVar("ExpressSequence", sequence, FRAMERATE);
  530.     if (!var) return;
  531.     frame = (int) floor(time * GetReal(var) + 0.5);
  532.  
  533.     InhibitLogging(true);
  534.     MakeVar(sequence, TRACKS);
  535.     var = GetVar(sequence, TRACKS);
  536.     if (var)
  537.     {
  538.     elements = ELEMENTS(var);
  539.     for (k = 0; k < DIMS(var)[0]; ++k)
  540.     {
  541.         ExpressTrack(elements[k], frame);
  542.     }
  543.     }
  544.     InhibitLogging(false);
  545. }
  546.  
  547. static ObjPtr ChangeSequenceTime(control)
  548. ObjPtr control;
  549. /*Changes the time in a sequence in response to control*/
  550. {
  551.     ObjPtr repObj;
  552.  
  553.     repObj = GetObjectVar("ChangedSequenceTime", control, REPOBJ);
  554.     if (repObj)
  555.     {
  556.     SetVar(repObj, TIME, GetValue(control));
  557.     ExpressSequence(repObj);
  558.     }
  559.  
  560.     return ObjTrue;
  561. }
  562.  
  563. static ObjPtr ShowSequenceControls(object, windowName)
  564. ObjPtr object;
  565. char *windowName;
  566. /*Makes a new control window to control sequence object*/
  567. {
  568.     WinInfoPtr controlWindow;
  569.     ObjPtr var;
  570.     ObjPtr panel;
  571.     ObjPtr contents;
  572.     ObjPtr control;
  573.     int left, right, bottom, top, width;
  574.     WinInfoPtr dialogExists;
  575.  
  576.     GetTemplateBounds(SequenceTemplate, "Panel", &left, &right, &bottom, &top);
  577.  
  578.  
  579.     dialogExists = DialogExists((WinInfoPtr) object, NewString("Controls"));
  580.     controlWindow = GetDialog((WinInfoPtr) object, NewString("Controls"), windowName, 
  581.     (right - left), (top - bottom), 1280, 1024, WINUI);
  582.     
  583.     if (!dialogExists)
  584.     {
  585.     SetVar((ObjPtr) controlWindow, REPOBJ, object);
  586.  
  587.     /*Put in a help string*/
  588.     SetVar((ObjPtr) controlWindow, HELPSTRING,
  589.         NewString("This window shows controls for a an animation sequence.  Using the controls in this \
  590. window, you can define keyframes and produce mini-movies."));
  591.  
  592.     /*Add in a panel*/
  593.     panel = TemplatePanel(SequenceTemplate, "Panel");
  594.     if (!panel)
  595.     {
  596.         return ObjFalse;
  597.     }
  598.     contents = GetVar((ObjPtr) controlWindow, CONTENTS);
  599.     PrefixList(contents, panel);
  600.     SetVar(panel, PARENT, (ObjPtr) controlWindow);
  601.  
  602.     contents = GetVar(panel, CONTENTS);
  603.  
  604.     /*Make a new track control to hold the tracks*/
  605.     control = TemplateTrackControl(SequenceTemplate, "Animation Tracks",
  606.                   0.0, 10.0);
  607.     SetVar(control, PARENT, panel);
  608.     SetVar(control, REPOBJ, object);
  609.     PrefixList(contents, control);
  610.     SetVar(control, HELPSTRING,
  611.         NewString("This control allows you to do lots of neat stuff with \
  612. animation."));
  613.     SetVar(control, STICKINESS, NewInt(STICKYLEFT + STICKYRIGHT + STICKYBOTTOM + STICKYTOP));
  614.     SetMethod(control, CHANGEDVALUE, ChangeSequenceTime);
  615.  
  616.     control = TemplateCheckBox(SequenceTemplate, "Automatically Add New Keyframes", false);
  617.     if (control)
  618.     {
  619.         SetVar(control, PARENT, panel);
  620.         PrefixList(contents, control);
  621.         SetVar(control, HELPSTRING,
  622.         NewString("When this check box is on, anything you do to any window or visualization \
  623. object will automatically add new keyframes at the time given by the track cursor."));
  624.         SetVar(control, INHIBITRECORDING, ObjTrue);
  625.         AssocDirectControlWithVar(control, object, RECORDING);
  626.         SetVar(control, STICKINESS, NewInt(STICKYLEFT + STICKYBOTTOM));
  627.     }
  628.     }
  629.     return (ObjPtr) controlWindow;
  630. }
  631.  
  632. static ObjPtr DrawTrackName(track, l, r, b, t)
  633. ObjPtr track;
  634. int l, r, b, t;
  635. /*Draws a track name within l, r, b, t*/
  636. {
  637.     int texty;
  638.     ObjPtr name;
  639.     ObjPtr subTracks;
  640.     int k;
  641.     ObjPtr *elements;
  642.  
  643.     MakeVar(track, APPEARANCE);
  644.  
  645.     texty = t - TC_CELLHEIGHT / 2 - TCFONTSIZE / 2 + TC_TEXTBUP;
  646.  
  647.     FillUIRect(l, r, t - TC_CELLHEIGHT, t, IsSelected(track) ? UIYELLOW : UIGRAY62);
  648.  
  649.     SetUIColor(UIBLACK);
  650.     name = GetVar(track,  NAME);
  651.     if (name)
  652.     {
  653.     DrawAString(LEFTALIGN, l + 1 + TCTEXTLOFF,
  654.             texty, GetString(name)); 
  655.     }
  656.     else
  657.     {
  658.     DrawAString(LEFTALIGN, l + 1 + TCTEXTLOFF,
  659.             texty, "?");
  660.     }
  661.  
  662.     if (GetPredicate(track, EXPANDEDP))
  663.     {
  664.     /*Draw the subtracks*/
  665.     ObjPtr var;
  666.     FuncTyp method;
  667.  
  668.     MakeVar(track, SUBTRACKS);
  669.     subTracks = GetVar(track, SUBTRACKS);
  670.     if (subTracks)
  671.     {
  672.         t -= TC_CELLHEIGHT;
  673.         elements = ELEMENTS(subTracks);
  674.         for (k = 0; k < DIMS(subTracks)[0]; ++k)
  675.         {
  676.  
  677.         MakeVar(elements[k], TRACKHEIGHT);
  678.         var = GetVar(elements[k], TRACKHEIGHT);
  679.         if (var)
  680.         {
  681.             b = t - GetInt(var);
  682.  
  683.             method = GetMethod(elements[k], DRAWNAME);
  684.             if (method)
  685.             {
  686.             (*method)(elements[k], l, r, b, t);
  687.             }
  688.             t = b;
  689.         }
  690.         }
  691.     }
  692.     }
  693.  
  694.     return ObjTrue;
  695. }
  696.  
  697. #ifdef PROTO
  698. static void DrawSubTrackMarker(int x, int y)
  699. #else
  700. static void DrawSubTrackMarker(x, y)
  701. int x, y;
  702. #endif
  703. /*Draws a subtrack keyframe marker at x, y*/
  704. {
  705.     int left, right, bottom, top;
  706.  
  707.     left = x - TC_STMARKHWIDTH;
  708.     right = x + TC_STMARKHWIDTH + 1;
  709.     bottom = y - TC_STMARKHHEIGHT;
  710.     top = y + TC_STMARKHHEIGHT + 1;
  711.  
  712.     /*face*/
  713.     FillUIRect(left + TC_STMARKEDGE, right - TC_STMARKEDGE, 
  714.         bottom + TC_STMARKEDGE, top - TC_STMARKEDGE, UIBACKGROUND);
  715.  
  716.     /* bottom */
  717.     SetUIColor(UIBOTTOMEDGE);
  718.     FillIntQuad( left, bottom,
  719.          right, bottom,
  720.          right - TC_STMARKEDGE, bottom + TC_STMARKEDGE,
  721.          left + TC_STMARKEDGE, bottom + TC_STMARKEDGE);
  722.  
  723.     /* left */
  724.     SetUIColor(UILEFTEDGE);
  725.     FillIntQuad( left,  bottom,
  726.          left + TC_STMARKEDGE, bottom + TC_STMARKEDGE,
  727.          left + TC_STMARKEDGE, top - TC_STMARKEDGE,
  728.          left, top);
  729.  
  730.     /* right */
  731.     SetUIColor(UIRIGHTEDGE);
  732.     FillIntQuad( right - TC_STMARKEDGE, bottom + TC_STMARKEDGE,
  733.          right, bottom,
  734.          right, top,
  735.          right - TC_STMARKEDGE, top - TC_STMARKEDGE);
  736.  
  737.     /* top */
  738.     SetUIColor(UITOPEDGE);
  739.     FillIntQuad( left + TC_STMARKEDGE, top - TC_STMARKEDGE,
  740.          right - TC_STMARKEDGE, top - TC_STMARKEDGE,
  741.          right, top,
  742.          left, top);
  743. }
  744.  
  745. #ifdef PROTO
  746. static void DrawTrackMarker(int x, int y)
  747. #else
  748. static void DrawTrackMarker(x, y)
  749. int x, y;
  750. #endif
  751. /*Draws a subtrack keyframe marker at x, y*/
  752. {
  753.     int left, right, bottom, top;
  754.  
  755.     left = x - TC_STMARKHWIDTH;
  756.     right = x + TC_STMARKHWIDTH + 1;
  757.     bottom = y - TC_STMARKHHEIGHT;
  758.     top = y + TC_STMARKHHEIGHT + 1;
  759.  
  760.     /* face */
  761.     FillUIRect(left, right, bottom, top - 1, UIBACKGROUND);
  762.  
  763.     /* top */
  764.     DrawUILine(left, top - 1, right, top - 1, UISHARPTOPEDGE);
  765.  
  766.     /* right */
  767.     DrawUILine(right, top - 1, right, bottom, UISHARPRIGHTEDGE);
  768.  
  769.     /* left */
  770.     DrawUILine(left - 1, bottom, left - 1, top - 1, UISHARPLEFTEDGE);
  771.  
  772.     /* bottom */
  773.     DrawUILine(left, bottom, right, bottom, UISHARPBOTTOMEDGE);
  774.  
  775.     /* line */
  776.     DrawUILine(x, bottom + 1, x, top - 2, UIBLACK);
  777. }
  778.  
  779. static ObjPtr DrawTrackLine(track, l, r, b, t, minTime, maxTime)
  780. ObjPtr track;
  781. int l, r, b, t;
  782. real minTime, maxTime;
  783. /*Draws a track name within l, r, b, t between minTime and maxTime*/
  784. {
  785.     int middle;
  786.     ObjPtr name, sequence;
  787.     ObjPtr *subTracks, *keyframes;
  788.     int k;
  789.     ObjPtr var, keyframesVar;
  790.     int nSubtracks, nKeyframes;
  791.     real frameWidth;
  792.     int pixel, curFrame, testFrame, bestFrame;
  793.     int index;
  794.     Bool anyToDraw;
  795.     real time;
  796.  
  797.     MakeVar(track, APPEARANCE);
  798.  
  799.     middle = t - TC_CELLHEIGHT / 2;
  800.  
  801. #if 0
  802.     DrawUILine(l, middle + 1, r, middle + 1, UIYELLOW);
  803.     DrawUILine(l, middle, r, middle, UIYELLOW);
  804. #endif
  805.  
  806.     /*Get the sequence that owns this track -> sequence*/
  807.     sequence = GetObjectVar("DrawTrackLine", track, PARENT);
  808.     if (!sequence) return ObjFalse;
  809.  
  810.     /*Get the frame width for converting from time to pixels*/
  811.     MakeVar(sequence, FRAMERATE);
  812.     var = GetRealVar("DrawSubTrackLine", sequence, FRAMERATE);
  813.     if (var)
  814.     {
  815.     frameWidth = 1.0 / GetReal(var);
  816.     }
  817.     else
  818.     {
  819.     frameWidth = 1.0 / 30.0;
  820.     }
  821.  
  822.     /*Get the subtracks*/
  823.     MakeVar(track, SUBTRACKS);
  824.     var = GetVar(track, SUBTRACKS);
  825.     if (var)
  826.     {
  827.     subTracks = ELEMENTS(var);
  828.     nSubtracks = DIMS(var)[0];
  829.     }
  830.     else
  831.     {
  832.     subTracks = (ObjPtr *) 0;
  833.     }
  834.  
  835.  
  836.     /*Get starting pixel*/
  837.     pixel = l - TC_STMARKHWIDTH;
  838.  
  839.     /*Get starting frame*/
  840.     curFrame = floor(P2T(pixel) / frameWidth + 0.5);
  841.     if (curFrame < 0) curFrame = 0;
  842.  
  843.     if (subTracks)
  844.     {
  845.     /*Draw the track summary*/
  846.  
  847.     /*Go through all the keyframes, setting up indices*/
  848.     for (k = 0; k < nSubtracks; ++k)
  849.     {
  850.         keyframesVar = GetVar(subTracks[k], KEYFRAMES);
  851.         if (keyframesVar)
  852.         {
  853.         keyframes = ELEMENTS(keyframesVar);
  854.         nKeyframes = DIMS(keyframesVar)[0];
  855.     
  856.         /*Get the index of the first keyframe to draw*/
  857.         index = SearchIntVar(keyframesVar, WHICHFRAME, curFrame);
  858.         if (index > 0) --index;
  859.  
  860.         /*Stick it into the keyframe*/
  861.         SetVar(keyframesVar, INDEX, NewInt(index));
  862.         }
  863.     }
  864.  
  865.     do
  866.     {
  867.         /*Find keyframe which has lowest WHICHFRAME greater than or
  868.           equal to curFrame, automatically advancing anything less
  869.           than curFrame*/
  870.  
  871.         bestFrame = 999999999;
  872.         anyToDraw = false;
  873.  
  874.         for (k = 0; k < nSubtracks; ++k)
  875.         {
  876.         keyframesVar = GetVar(subTracks[k], KEYFRAMES);
  877.         if (keyframesVar)
  878.         {
  879.             keyframes = ELEMENTS(keyframesVar);
  880.             nKeyframes = DIMS(keyframesVar)[0];
  881.  
  882.             var = GetIntVar("DrawTrackLine", keyframesVar, INDEX);
  883.             if (!var) continue;
  884.             index = GetInt(var);
  885.  
  886.             if (index >= nKeyframes) continue;
  887.  
  888.             var = GetIntVar("DrawTrackLine", keyframes[index], WHICHFRAME);
  889.             if (!var) continue;
  890.  
  891.             while (index < nKeyframes && (testFrame = GetInt(var)) < curFrame)
  892.             {
  893.             ++index;
  894.             SetVar(keyframesVar, INDEX, NewInt(index));
  895.             if (index < nKeyframes)
  896.             {
  897.                 var = GetIntVar("DrawTrackLine", keyframes[index], WHICHFRAME);
  898.             }
  899.             }
  900.             if (index >= nKeyframes) continue;
  901.  
  902.             bestFrame = MIN(bestFrame, testFrame);
  903.             anyToDraw = true;
  904.         }
  905.         }
  906.  
  907.         /*Now we should have a bestFrame*/
  908.         if (anyToDraw)
  909.         {
  910.         /*Print out the bestFrame*/
  911.         time = bestFrame * frameWidth;
  912.         pixel = T2P(time);
  913.         DrawSubTrackMarker(pixel, middle);
  914.  
  915.         /*Go to next frame*/
  916.         curFrame = bestFrame + 1;
  917.         }
  918.  
  919.     } while (anyToDraw && pixel < r + TC_STMARKHWIDTH);
  920.     }
  921.  
  922.     if (GetPredicate(track, EXPANDEDP))
  923.     {
  924.     /*Draw the subtracks*/
  925.     FuncTyp method;
  926.  
  927.     if (subTracks)
  928.     {
  929.         t -= TC_CELLHEIGHT;
  930.         for (k = 0; k < nSubtracks; ++k)
  931.         {
  932.  
  933.         MakeVar(subTracks[k], TRACKHEIGHT);
  934.         var = GetVar(subTracks[k], TRACKHEIGHT);
  935.         if (var)
  936.         {
  937.             b = t - GetInt(var);
  938.  
  939.             method = GetMethod(subTracks[k], DRAWTRACK);
  940.             if (method)
  941.             {
  942.             (*method)(subTracks[k], l, r, b, t, minTime, maxTime);
  943.             }
  944.             t = b;
  945.         }
  946.         }
  947.     }
  948.     }
  949.  
  950.     return ObjTrue;
  951. }
  952.  
  953.  
  954. static ObjPtr DrawSubTrackLine(track, l, r, b, t, minTime, maxTime)
  955. ObjPtr track;
  956. int l, r, b, t;
  957. real minTime, maxTime;
  958. /*Draws a subtrack within l, r, b, t between minTime and maxTime*/
  959. {
  960.     int middle;
  961.     ObjPtr subTracks;
  962.     ObjPtr keyframes;
  963.     ObjPtr sequence;
  964.     ObjPtr *elements;
  965.     int pixel;
  966.     real testTime;
  967.     real time;
  968.     int testFrame;
  969.     real frameWidth;
  970.     int curFrame, nextFrame;
  971.     long index;
  972.     int startPixel;
  973.     ObjPtr var;
  974.     ObjPtr snap1, snap2;
  975.  
  976.     /*Get the elements to draw*/
  977.     keyframes = GetVar(track, KEYFRAMES);
  978.     if (!keyframes) return ObjTrue;
  979.     elements = ELEMENTS(keyframes);
  980.  
  981.     /*Get middle of cell for drawing things*/
  982.     middle = t - TC_CELLHEIGHT / 2;
  983.  
  984.     /*Get the sequence that owns this  subtrack -> track -> sequence*/
  985.     sequence = GetObjectVar("DrawSubTrackLine", track, PARENT);
  986.     if (!sequence) return ObjFalse;
  987.     sequence = GetObjectVar("DrawSubTrackLine", sequence, PARENT);
  988.     if (!sequence) return ObjFalse;
  989.  
  990.     /*Get the frame width for converting from time to pixels*/
  991.     MakeVar(sequence, FRAMERATE);
  992.     var = GetRealVar("DrawSubTrackLine", sequence, FRAMERATE);
  993.     if (var)
  994.     {
  995.     frameWidth = 1.0 / GetReal(var);
  996.     }
  997.     else
  998.     {
  999.     frameWidth = 1.0 / 30.0;
  1000.     }
  1001.  
  1002.     /*Get starting pixel*/
  1003.     pixel = l - TC_STMARKHWIDTH;
  1004.  
  1005.     /*Get starting frame*/
  1006.     curFrame = floor(P2T(pixel) / frameWidth + 0.5);
  1007.     if (curFrame < 0) curFrame = 0;
  1008.  
  1009.     /*Get the index of the first keyframe to draw*/
  1010.     index = SearchIntVar(keyframes, WHICHFRAME, curFrame);
  1011.     if (index > 0) --index;
  1012.  
  1013.     var = GetIntVar("DrawSubTrackLine", elements[index], WHICHFRAME);
  1014.     if (!var)
  1015.     {
  1016.     return ObjFalse;
  1017.     }
  1018.     curFrame = GetInt(var);
  1019.  
  1020.     do
  1021.     {
  1022.     /*Get the next frame*/
  1023.     if (index + 1 >= DIMS(keyframes)[0])
  1024.     {
  1025.         nextFrame = -1;
  1026.     }
  1027.     else
  1028.     {
  1029.         var = GetIntVar("DrawSubTrackLine", elements[index + 1], WHICHFRAME);
  1030.         if (!var)
  1031.         {
  1032.         return ObjFalse;
  1033.         }
  1034.         nextFrame = GetInt(var);
  1035.     }
  1036.  
  1037.     /*Print out the curFrame*/
  1038.     time = curFrame * frameWidth;
  1039.     pixel = T2P(time);
  1040.     DrawSubTrackMarker(pixel, middle);
  1041.  
  1042.     if (nextFrame < 0)
  1043.     {
  1044.         /*That's it, don't bother any more*/
  1045.         break;
  1046.     }
  1047.  
  1048.     /*Draw the line to the next frame*/
  1049.     startPixel = pixel + TC_STMARKHWIDTH + 1;
  1050.     time = nextFrame * frameWidth;
  1051.     pixel = T2P(time);
  1052.  
  1053.     snap1 = GetVar(elements[index], SNAPSHOT);
  1054.     snap2 = GetVar(elements[index + 1], SNAPSHOT);
  1055.  
  1056.     if (startPixel < pixel - TC_STMARKHWIDTH)
  1057.     {
  1058.         /*Draw a continuation line*/
  1059.         FillUIRect(startPixel, pixel - TC_STMARKHWIDTH,
  1060.             middle - 1, middle + 1,
  1061.             EqualSnapshots(snap1, snap2) ? UIGRAY50 : UIBLUE);
  1062.     }
  1063.  
  1064.     /*Advance index and curFrame*/
  1065.     curFrame = nextFrame;
  1066.     ++index;
  1067.  
  1068.     } while (nextFrame >= 0 && pixel < r + TC_STMARKHWIDTH);
  1069.  
  1070.     return ObjTrue;
  1071. }
  1072.  
  1073. static ObjPtr DrawSubTrackName(track, l, r, b, t)
  1074. ObjPtr track;
  1075. int l, r, b, t;
  1076. /*Draws a subtrack name within l, r, b, t*/
  1077. {
  1078.     int texty;
  1079.     ObjPtr name;
  1080.     ObjPtr subTracks;
  1081.     int k;
  1082.     ObjPtr *elements;
  1083.  
  1084.     MakeVar(track, APPEARANCE);
  1085.  
  1086.     texty = t - TC_CELLHEIGHT / 2 - TCFONTSIZE / 2;
  1087.  
  1088.     FillUIRect(l, r, t - TC_CELLHEIGHT, t, IsSelected(track) ? UIYELLOW : UIGRAY62);
  1089.  
  1090.     SetUIColor(UIBLACK);
  1091.     name = GetVar(track,  NAME);
  1092.     if (name)
  1093.     {
  1094.     DrawAString(LEFTALIGN, l + 1 + TCSUBTEXTLOFF,
  1095.             texty, GetString(name)); 
  1096.     }
  1097.     else
  1098.     {
  1099.     DrawAString(LEFTALIGN, l + 1 + TCSUBTEXTLOFF,
  1100.             texty, "?");
  1101.     }
  1102.  
  1103.     return ObjTrue;
  1104. }
  1105.  
  1106. static ObjPtr MakeTrackAppearance(track)
  1107. ObjPtr track;
  1108. /*Makes a track's appearance*/
  1109. {
  1110.     ImInvalid(track);
  1111.     SetVar(track, APPEARANCE, ObjTrue);
  1112.     return ObjTrue;
  1113. }
  1114.  
  1115. static ObjPtr MakeSubTrackAppearance(track)
  1116. ObjPtr track;
  1117. /*Makes a subtrack's appearance*/
  1118. {
  1119.     ImInvalid(track);
  1120.     SetVar(track, APPEARANCE, ObjTrue);
  1121.     return ObjTrue;
  1122. }
  1123.  
  1124. static ObjPtr PressTrackName(track, x, y, flags)
  1125. ObjPtr track;
  1126. int x, y;
  1127. long flags;
  1128. /*Press in a track control name section.  y is negative from top*/
  1129. {
  1130.     ObjPtr parent;
  1131.  
  1132.     if (y > -TC_CELLHEIGHT)
  1133.     {
  1134.     /*It's a press in the main name*/
  1135.     if (TOOL(flags) == T_HELP)
  1136.     {
  1137.         ContextHelp(track);
  1138.         return ObjTrue;
  1139.     }
  1140.  
  1141.     if (TOOL(flags) == T_ROTATE)
  1142.     {
  1143.         flags |= F_EXTEND;
  1144.     }
  1145.  
  1146.     if (flags & F_EXTEND)
  1147.     {
  1148.         Select(track, IsSelected(track) ? false : true);
  1149.     }
  1150.     else
  1151.     {
  1152.         if (!IsSelected(track))
  1153.         {
  1154.         DeselectAll();
  1155.         Select(track, true);
  1156.         }
  1157.         if (flags & F_DOUBLECLICK)
  1158.         {
  1159.         /*Expand or contract*/
  1160.         SetVar(track, EXPANDEDP, GetPredicate(track, EXPANDEDP) ? ObjFalse : ObjTrue);
  1161.  
  1162.         /*Have to touch parent's TRACKS*/
  1163.         parent = GetObjectVar("PressTrackName", track, PARENT);
  1164.         if (parent)
  1165.         {
  1166.             SetVar(parent, TRACKS, GetVar(parent, TRACKS));
  1167.         }
  1168.  
  1169.         /*DIKEO log*/
  1170.         }
  1171.     }
  1172.     }
  1173.     else if (GetPredicate(track, EXPANDEDP))
  1174.     {
  1175.     /*It may be a press in a subtrack*/
  1176.     int ty;
  1177.     ObjPtr var;
  1178.     ObjPtr subTracks;
  1179.     int height;
  1180.     long k;
  1181.     ObjPtr *elements;
  1182.  
  1183.     ty = - TC_CELLHEIGHT;
  1184.  
  1185.     subTracks = GetVar(track, SUBTRACKS);
  1186.     if (subTracks)
  1187.     {
  1188.         elements = ELEMENTS(subTracks);
  1189.         for (k = 0; k < DIMS(subTracks)[0]; ++k)
  1190.         {
  1191.         MakeVar(elements[k], TRACKHEIGHT);
  1192.         var = GetVar(elements[k], TRACKHEIGHT);
  1193.         if (var)
  1194.         {
  1195.             height = GetInt(var);
  1196.             if ((ty - height) < y &&
  1197.              (ty >= y)) break;
  1198.             ty -= height;
  1199.         }
  1200.         }
  1201.  
  1202.         if (k < DIMS(subTracks)[0])
  1203.         {
  1204.         /*It is a press in a subtrack*/
  1205.         FuncTyp method;
  1206.  
  1207.         method = GetMethod(elements[k], PRESSNAME);
  1208.         if (method)
  1209.         {
  1210.             (*method)(elements[k], x, y - ty, flags);
  1211.         }
  1212.         }
  1213.     }
  1214.     }
  1215.  
  1216.     return ObjTrue;
  1217. }
  1218.  
  1219. static ObjPtr PressSubTrackName(track, x, y, flags)
  1220. ObjPtr track;
  1221. int x, y;
  1222. long flags;
  1223. /*Press in a subtrack control name section.  y is negative from top*/
  1224. {
  1225.     ObjPtr parent;
  1226.  
  1227.     if (TOOL(flags) == T_HELP)
  1228.     {
  1229.         ContextHelp(track);
  1230.         return ObjTrue;
  1231.     }
  1232.  
  1233.     if (TOOL(flags) == T_ROTATE)
  1234.     {
  1235.         flags |= F_EXTEND;
  1236.     }
  1237.  
  1238.     if (flags & F_EXTEND)
  1239.     {
  1240.         Select(track, IsSelected(track) ? false : true);
  1241.     }
  1242.     else
  1243.     {
  1244.         if (!IsSelected(track))
  1245.         {
  1246.         DeselectAll();
  1247.         Select(track, true);
  1248.         }
  1249.     }
  1250.  
  1251.     /*Make its parent invalid*/
  1252.     parent = GetVar(track, PARENT);
  1253.     SetVar(parent, APPEARANCE, ObjTrue);
  1254.  
  1255.     return ObjTrue;
  1256. }
  1257.  
  1258. static ObjPtr MakeTrackHeight(track)
  1259. ObjPtr track;
  1260. /*Makes a track's TRACKHEIGHT*/
  1261. {
  1262.     int height;
  1263.  
  1264.     height = TC_CELLHEIGHT;
  1265.  
  1266.     if (GetPredicate(track, EXPANDEDP))
  1267.     {
  1268.     ObjPtr subTracks;
  1269.  
  1270.     MakeVar(track, SUBTRACKS);
  1271.     subTracks = GetVar(track, SUBTRACKS);
  1272.     if (subTracks)
  1273.     {
  1274.         ObjPtr *elements;
  1275.         ObjPtr var;
  1276.         int k;
  1277.  
  1278.         elements = ELEMENTS(subTracks);
  1279.  
  1280.         for (k = 0; k < DIMS(subTracks)[0]; ++k)
  1281.         {
  1282.         MakeVar(elements[k], TRACKHEIGHT);
  1283.         var = GetVar(elements[k], TRACKHEIGHT);
  1284.         if (var)
  1285.         {
  1286.             height += GetInt(var);
  1287.         }
  1288.         }
  1289.     }
  1290.     }
  1291.  
  1292.     SetVar(track, TRACKHEIGHT, NewInt(height));
  1293.  
  1294.     return ObjTrue;
  1295. }
  1296.  
  1297. static ObjPtr MakeSubTrackHeight(track)
  1298. ObjPtr track;
  1299. /*Makes a subtrack's TRACKHEIGHT*/
  1300. {
  1301.     SetVar(track, TRACKHEIGHT, NewInt(TC_CELLHEIGHT));
  1302.     return ObjTrue;
  1303. }
  1304.  
  1305. static ObjPtr SelectTrack(track, whether)
  1306. ObjPtr track;
  1307. Bool whether;
  1308. /*Extra stuff for selecting a track; selects all its subtracks*/
  1309. {
  1310.     ObjPtr subTracks;
  1311.     ObjPtr *elements;
  1312.     long k;
  1313.  
  1314.     subTracks = GetVar(track, SUBTRACKS);
  1315.     if (subTracks)
  1316.     {
  1317.     elements = ELEMENTS(subTracks);
  1318.     for (k = 0; k < DIMS(subTracks)[0]; ++k)
  1319.     {
  1320.         Select(elements[k], whether);
  1321.     }
  1322.     }
  1323. }
  1324.  
  1325. #ifdef PROTO
  1326. void DefineBetterVarName(NameTyp var, char *name)
  1327. #else
  1328. void DefineBetterVarName(var, name)
  1329. NameTyp var;
  1330. char *name;
  1331. #endif
  1332. /*Defines a better var name for variable var as name*/
  1333. {
  1334.     int k;
  1335.  
  1336.     if (var >= nBetterVarNames)
  1337.     {
  1338.     if (betterVarNames)
  1339.     {
  1340.         betterVarNames = (char **) Realloc(betterVarNames, (var + 1) * sizeof(char *));
  1341.     }
  1342.     else
  1343.     {
  1344.         betterVarNames = (char **) Alloc((var + 1) * sizeof(char *));
  1345.     }
  1346.     for (k = nBetterVarNames; k <= var; ++k)
  1347.     {
  1348.         betterVarNames[k] = NULL;
  1349.     }
  1350.     nBetterVarNames = var + 1;
  1351.     }
  1352.     SAFEFREE(betterVarNames[var]);
  1353.     betterVarNames[var] = (char *) Alloc(strlen(name) + 1);
  1354.     strcpy(betterVarNames[var], name);
  1355. }
  1356.  
  1357. #ifdef PROTO
  1358. char *GetGoodVarName(NameTyp var)
  1359. #else
  1360. char *GetGoodVarName(var)
  1361. NameTyp var;
  1362. #endif
  1363. /*Gets a good var name for variable var and returns it.  Return value is
  1364. volatile and disappears after next call to GetGoodVarName.*/
  1365. {
  1366.     char *name;
  1367.     static char processedName[300];
  1368.     int k;
  1369.  
  1370.     if (var < nBetterVarNames && betterVarNames[var])
  1371.     {
  1372.     strcpy(processedName, betterVarNames[var]);
  1373.     }
  1374.     else
  1375.     {
  1376.     name = GetInternalString(var);
  1377.     strcpy(processedName, name);
  1378.  
  1379.     for (k = 1; processedName[k]; ++k)
  1380.     {
  1381.     processedName[k] = tolower(processedName[k]);
  1382.     }
  1383.     }
  1384.     return processedName;
  1385. }
  1386.  
  1387. #ifdef PROTO
  1388. void RecordObjectVar(ObjPtr object, NameTyp whichVar)
  1389. #else
  1390. void RecordObjectVar(object, whichVar)
  1391. ObjPtr object;
  1392. NameTyp whichVar;
  1393. #endif
  1394. /*Records the current value of an object var in recording sequences*/
  1395. {
  1396.     ObjPtr keyList, result;
  1397.  
  1398.     keyList = NewList();
  1399.     PostfixList(keyList, NewSymbol(CLASSID));
  1400.     PostfixList(keyList, NewInt(CLASS_SEQUENCE));
  1401.     PostfixList(keyList, NewSymbol(RECORDING));
  1402.     PostfixList(keyList, ObjTrue);
  1403.  
  1404.     result = SearchDatabase(keyList);
  1405.     if (result && LISTOF(result))
  1406.     {
  1407.     ThingListPtr runner;
  1408.     char *name;
  1409.  
  1410.     runner = LISTOF(result);
  1411.     while (runner)
  1412.     {
  1413.         ObjPtr track, snapshot;
  1414.         real time;
  1415.         real frameWidth;
  1416.         int whichFrame;
  1417.         ObjPtr var;
  1418.  
  1419.         name = GetGoodVarName(whichVar);
  1420.  
  1421.         track = TrackVarGroupWithinSequence(runner -> thing, object, name, NULLOBJ);
  1422.         if (track)
  1423.         {
  1424.         MakeVar(runner -> thing, FRAMERATE);
  1425.         var = GetVar(runner -> thing, FRAMERATE);
  1426.         if (var)
  1427.         {
  1428.             frameWidth = 1.0 / GetReal(var);
  1429.         }
  1430.         else
  1431.         {
  1432.             frameWidth = 1.0 / 30.0;
  1433.         }
  1434.  
  1435.         var = GetVar(runner -> thing, TIME);
  1436.         if (var)
  1437.         {
  1438.             time = GetReal(var);
  1439.         }
  1440.         else
  1441.         {
  1442.             time = 0.0;
  1443.         }
  1444.  
  1445.         whichFrame = (int) floor(time / frameWidth + 0.5);
  1446.         
  1447.         snapshot = TakeSingleVarSnapshot(object, whichVar);
  1448.         InsertKeySnapshot(track, whichFrame, snapshot);
  1449.         }
  1450.  
  1451.         runner = runner -> next;
  1452.     }
  1453.     }
  1454. }
  1455.  
  1456. #ifdef PROTO
  1457. ObjPtr TrackBoundsInvalid(ObjPtr object, unsigned long changeCount)
  1458. #else
  1459. ObjPtr TrackBoundsInvalid(object, changeCount)
  1460. ObjPtr object;
  1461. unsigned long changeCount;
  1462. #endif
  1463. /*For an track, tests to see if it needs drawing.  Returns
  1464.   NULLOBJ    if it does not
  1465.   ObjTrue    it it needs to be redrawn but does not know where
  1466.  
  1467.   In order for an object to be declared invalid, its changed bounds
  1468.   must have been changed more recently than changeCount
  1469. */
  1470. {
  1471.     ObjPtr subTracks;
  1472.  
  1473.     MakeVar(object, APPEARANCE);
  1474.  
  1475.     MakeVar(object, CHANGEDBOUNDS);
  1476.     if (GetVarChangeCount(object, CHANGEDBOUNDS) > changeCount)
  1477.     {
  1478.     /*Object is not good, so return true*/
  1479.     return ObjTrue;
  1480.     }
  1481.  
  1482.     MakeVar(object, SUBTRACKS);
  1483.     subTracks = GetVar(object, SUBTRACKS);
  1484.     if (subTracks && IsObjArray(subTracks))
  1485.     {
  1486.     /*Still, maybe some of the contents need to be drawn*/
  1487.     ObjPtr *elements;
  1488.     long k;
  1489.  
  1490.     elements = ELEMENTS(subTracks);
  1491.  
  1492.     for (k = 0; k < DIMS(subTracks)[0]; ++k)
  1493.     {
  1494.         if (BoundsInvalid(elements[k], changeCount))
  1495.         {
  1496.         return ObjTrue;
  1497.         }
  1498.     }
  1499.     }
  1500.  
  1501.     return NULLOBJ;
  1502. }
  1503.  
  1504. #ifdef PROTO
  1505. void InitAnimation(void)
  1506. #else
  1507. void InitAnimation()
  1508. #endif
  1509. /*Initializes the animations*/
  1510. {
  1511.     sequenceClass = NewObject(NULLOBJ, 0L);
  1512.     SetVar(sequenceClass, CLASSID, NewInt(CLASS_SEQUENCE));
  1513.     SetMethod(sequenceClass, SHOWCONTROLS, NewControlWindow);
  1514.     SetMethod(sequenceClass, NEWCTLWINDOW, ShowSequenceControls);
  1515.     SetVar(sequenceClass, RECORDING, ObjFalse);
  1516.     SetVar(sequenceClass, TIME, NewReal(0.0));
  1517.     SetVar(sequenceClass, FRAMERATE, NewReal(30.0));
  1518.     AddToReferenceList(sequenceClass);
  1519.  
  1520.     trackClass = NewObject(NULLOBJ, 0L);
  1521.     AddToReferenceList(trackClass);
  1522.     DeclareDependency(trackClass, TRACKHEIGHT, EXPANDEDP);
  1523.     DeclareDependency(trackClass, TRACKHEIGHT, CHANGED);
  1524.     DeclareDependency(trackClass, TRACKHEIGHT, SUBTRACKS);
  1525.     SetMethod(trackClass, TRACKHEIGHT, MakeTrackHeight);
  1526.     SetMethod(trackClass, DRAWNAME, DrawTrackName);
  1527.     SetMethod(trackClass, DRAWTRACK, DrawTrackLine);
  1528.     DeclareDependency(trackClass, APPEARANCE, SELECTED);
  1529.     DeclareDependency(trackClass, APPEARANCE, TRACKHEIGHT);
  1530.     DeclareDependency(trackClass, APPEARANCE, CHANGED);
  1531.     DeclareDependency(trackClass, APPEARANCE, EXPANDEDP);
  1532.     SetMethod(trackClass, APPEARANCE, MakeTrackAppearance);
  1533.     SetMethod(trackClass, PRESSNAME, PressTrackName);
  1534.     SetMethod(trackClass, SELECT, SelectTrack);
  1535.     SetMethod(trackClass, BOUNDSINVALID, TrackBoundsInvalid);
  1536.  
  1537.     subTrackClass = NewObject(NULLOBJ, 0L);
  1538.     AddToReferenceList(subTrackClass);
  1539.     SetMethod(subTrackClass, TRACKHEIGHT, MakeSubTrackHeight);
  1540.     SetMethod(subTrackClass, DRAWNAME, DrawSubTrackName);
  1541.     SetMethod(subTrackClass, PRESSNAME, PressSubTrackName);
  1542.     DeclareDependency(subTrackClass, APPEARANCE, KEYFRAMES);
  1543.     DeclareDependency(subTrackClass, APPEARANCE, CHANGED);
  1544.     SetMethod(subTrackClass, APPEARANCE, MakeSubTrackAppearance);
  1545.     SetMethod(subTrackClass, DRAWTRACK, DrawSubTrackLine);
  1546.     SetMethod(subTrackClass, EXPRESS, ExpressDefaultSubTrack);
  1547.  
  1548.     keyFrameClass = NewObject(NULLOBJ, 0L);
  1549.     AddToReferenceList(keyFrameClass);
  1550.  
  1551.     DefineBetterVarName(ROTQUAT, "Rotation");
  1552.     DefineBetterVarName(FOCUSDIST, "Focus Distance");
  1553.     DefineBetterVarName(ISOVAL, "Isovalue");
  1554. }
  1555.  
  1556. #ifdef PROTO
  1557. void KillAnimation(void)
  1558. #else
  1559. void KillAnimation()
  1560. #endif
  1561. /*Kills animation*/
  1562. {
  1563.     int k;
  1564.     AddToReferenceList(keyFrameClass);
  1565.     RemoveFromReferenceList(subTrackClass);
  1566.     RemoveFromReferenceList(trackClass);
  1567.     RemoveFromReferenceList(sequenceClass);
  1568.     for (k = 0; k < nBetterVarNames; ++k)
  1569.     {
  1570.     SAFEFREE(betterVarNames[k]);
  1571.     }
  1572.     SAFEFREE(betterVarNames);
  1573. }
  1574.